﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace DevicesInt
{
    public class MibMyReader : IDisposable
    {
        private readonly string _fileName;
        private FileStream _fs;
        private bool _streamOpened = false;

        public MibMyReader(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentNullException("fileName");
            }
            if (!fileName.EndsWith(".my"))
            {
                throw new ArgumentException("file name must ends with .my");
            }
            _fileName = fileName;
            _fs = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            _streamOpened = true;
        }

        public void OpenStream(string fileName)
        {
            _fs.Close();
            _fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            _streamOpened = true;
        }

        public void CloseStream()
        {
            _fs.Close();
            _streamOpened = false;
        }

        public OidInfo FindDescription(string oid)
        {
            var l = new List<string> {oid};
            return FindDescriptions(l).FirstOrDefault();
        }

        public List<OidInfo> FindDescriptions(List<string> oids)
        {
            var toRet = new List<OidInfo>();
            if(!_streamOpened)
                throw new Exception("stream closed");
            var reader = new StreamReader(_fs);
            while (true)
            {
                string curLine;
                string curOid = "";
                bool contains = false;

                try
                {
                    curLine = ReadTrueString(reader);
                    if (curLine == null)
                        break;
                }
                catch (IOException)
                {
                    break;
                }

                //Определяем, есть в текущей строке искомый oid
                foreach (var oid in oids)
                {
                    //if (!curLine.Contains(oid))
                    //    continue;
                    if(!curLine.EndsWith(oid))
                        continue;
                    contains = true;
                    curOid = oid;
                    break;
                }

                if (!contains)
                    continue;

                //Если oid есть, работаем с ним

                try
                {
                    var info = CreateOidInfo(reader);
                    info.Oid = curOid;
                    toRet.Add(info);
                }
                catch (Exception)
                {
                    continue;
                }
            }

            reader.Close();

            return toRet;

        }

        private string RemoveTabsNTrim(string str)
        {
            var st = str.Replace("\t", "");
            st = st.Trim();
            return st;
        }

        private string ReadTrueString(StreamReader reader)
        {
            var st = reader.ReadLine();
            if (st == null)
                return null;
            return RemoveTabsNTrim(st);
        }

        private OidInfo CreateOidInfo(StreamReader reader)
        {
            var info = new OidInfo();

            info.Name = ReadTrueString(reader).Split(' ')[0];
            info.Syntax = new OidSyntax(ReadTrueString(reader));
            info.Access = ReadTrueString(reader).Split(' ')[1];
            info.Status = ReadTrueString(reader).Split(' ')[1];
            string description = "";
            reader.ReadLine();
            while (true)
            {
                var curStr = ReadTrueString(reader);
                if (curStr.StartsWith("::="))
                    break;
                description += curStr;
                description += Environment.NewLine;
            }
            description = description.Remove(description.Length - 2, 2);
            info.Description = new OidDescription(description);
            return info;
        }

        public void Dispose()
        {
            CloseStream();
        }
    }

    public struct OidInfo
    {
        public string Oid { get; set; }
        public string Name { get; set; }
        public OidSyntax Syntax { get; set; }
        public string Access { get; set; }
        public string Status { get; set; }
        public OidDescription Description { get; set; }
    }

    public class OidSyntax
    {
        public OidSyntax(string syntax)
        {
            Set(syntax);
        }

        public void Set(string syntax)
        {
            var splits = syntax.Split(' ');
            Type = splits[1];
            if(splits.Length > 2)
                CreateValues(splits[2]);
        }

        private void CreateValues(string valuesString)
        {
            Values = new List<OidValueVariant>();
            var splits = valuesString.Split(',');
            splits[0] = splits[0].TrimStart(new[] { '{' });
            splits[splits.Length - 1] = splits[splits.Length - 1].TrimEnd(new[] { '}' });

            foreach (var split in splits)
            {
                var more = split.Split(new[] {'(', ')'}, StringSplitOptions.RemoveEmptyEntries);
                Values.Add(new OidValueVariant {Value = more[0], Determinition = more[1]});
            }

        }

        public string Type { get; set; }
        public List<OidValueVariant> Values { get; set; }
    }

    public struct OidValueVariant
    {
        public string Value { get; set; }
        public string Determinition { get; set; }
    }

    public class OidDescription
    {
        public OidDescription(string description)
        {
            Set(description);
        }

        public void Set(string description)
        {
            Full = description;
            Full = Full.TrimStart(new[] { '"' });
            Full = Full.TrimEnd(new[] { '"' });
            var splits = Full.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            //splits[0] = splits[0].TrimStart(new[] {'"'});
            //splits[splits.Length - 1] = splits[splits.Length - 1].TrimEnd(new[] { '"' });
            bool first = true;
            foreach (var split in splits)
            {
                if (!split.Contains(':'))
                {
                    Text += split;
                    if (first)
                    {
                        Header = split.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries)[0];
                        first = false;
                    }
                }
            }
        }

        public string Full { get; set; }
        public string Text { get; set; }
        public string Header { get; set; }
    }
}
